package com.pkk.penguin.java.notepad.jdk.jdk18.stream;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.Data;
import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 流的测试
 *
 * @author kunkun.pei
 * @create 2021-06-11 16:41
 **/
public class StreamTest {

    @Test
    public void shiheng_25_20210813150910() {
        System.out.println("欢迎使用单元测试方法【shiheng_25()_20210813150910】");
        System.out.println("此方法测试描述：【】");
        List<SimpleClass> childSimple1 = Arrays.asList(new SimpleClass("1-3", 1), new SimpleClass("2-3", 2), new SimpleClass("3-3", 3));
        List<SimpleClass> childSimple = Arrays.asList(new SimpleClass("1-2", 1, childSimple1), new SimpleClass("2-2", 2), new SimpleClass("3-2", 3));
        List<SimpleClass> simpleClasses = Arrays.asList(new SimpleClass("1", 1, childSimple), new SimpleClass("2", 2), new SimpleClass("3", 3));

        ListIterator<SimpleClass> simpleClassListIterator = simpleClasses.listIterator();
        //List<SimpleClass> collect = StreamSupport.stream(Spliterators.spliteratorUnknownSize(simpleClassListIterator, Spliterator.ORDERED), false).filter(c -> CollectionUtil.isNotEmpty(c.getChild())).flatMap(a -> a.child.stream()).collect(Collectors.toList());
        //System.out.println(JSONObject.toJSONString(collect));


        List<SimpleClass> collect = convertToFlatmap(simpleClasses);
        collect.stream().forEach(c -> c.setChild(null));
        System.out.println("------------------");
        System.out.println(JSONObject.toJSONString(collect));
    }

    @Test
    public void shiheng_46_20210813172748() {
        System.out.println("欢迎使用单元测试方法【shiheng_46()_20210813172748】");
        System.out.println("此方法测试描述：【】");
        List<SimpleClass> childSimple1 = Arrays.asList(new SimpleClass("1-3", 1), new SimpleClass("2-3", 2), new SimpleClass("3-3", 3));
        List<SimpleClass> childSimple = Arrays.asList(new SimpleClass("1-2", 1, childSimple1), new SimpleClass("2-2", 2), new SimpleClass("3-2", 3));
        List<SimpleClass> simpleClasses = Arrays.asList(new SimpleClass("1", 1, childSimple), new SimpleClass("2", 2), new SimpleClass("3", 3));


        simpleClasses.stream().forEach(a -> {
            if (CollectionUtil.isNotEmpty(a.getChild())) {
                a.getChild().forEach(b -> {
                    if (CollectionUtil.isNotEmpty(b.getChild())) {

                    } else {

                    }
                });
            }
        });


    }


    public static List<SimpleClass> convertToFlatmap(List<SimpleClass> all) {
        return all.stream().filter(f -> ObjectUtil.isNotNull(f.getChild())).flatMap(child -> {
                    if (null == child) {
                        return all.stream().flatMap(c -> c.getChild().stream());
                    }
                    List<SimpleClass> childNew = new ArrayList<>(child.getChild());
                    Stream<SimpleClass> concat = Stream.concat(Stream.of(child), convertToFlatmap(childNew).stream());
                    return concat;
                }
        ).collect(Collectors.toList());
    }


    @Test
    public void shiheng_28_20210813144541() {
        System.out.println("欢迎使用单元测试方法【shiheng_28()_20210813144541】");
        System.out.println("此方法测试描述：【peek与map的不同，map有返回值，peek没有只消费】");


        List<String> collect = Stream.of("one", "two", "three", "four")
                .filter(e -> e.length() > 3)
                .peek(e -> System.out.println("Filtered value: " + e))
                .map(String::toUpperCase)
                .peek(e -> System.out.println("Mapped value: " + e))
                .collect(Collectors.toList());
        System.out.println(collect);
    }


    @Test
    public void shiheng_28_20210813103702() {
        System.out.println("欢迎使用单元测试方法【shiheng_28()_20210813103702】");
        System.out.println("此方法测试描述：【在map中返回null是会当成一个null对象的，需要对null对象过滤操作】");


        List<SimpleClass> collect = Stream.iterate(1, i -> i + 1).limit(100).map(a -> {
            if (Integer.valueOf("3").equals(a)) {
                return null;
            }
            return new SimpleClass(a);
        }).filter(Objects::nonNull).collect(Collectors.toList());
        System.out.println(JSONObject.toJSONString(collect));
    }


    @Test
    public void shiheng_24_20210721180037() throws InterruptedException, ExecutionException, TimeoutException {
        System.out.println("欢迎使用单元测试方法【shiheng_24()_20210721180037】");
        System.out.println("此方法测试描述：【】");

        StopWatch stopWatch = new StopWatch();
        stopWatch.start("CompletableFuture");
        Stream.iterate(0, i -> i + 1).limit(10).parallel().forEach(q -> {
            CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> supplyAsync(1000L));
            try {
                //String s = stringCompletableFuture.get(2000L, TimeUnit.MILLISECONDS);
                String s = stringCompletableFuture.get();
                System.out.println(q + "--->" + s);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
    }


    private String supplyAsync(long time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return Thread.currentThread().getName() + "获取数据了";
    }


    @Test
    public void shiheng_24_20210721174640() {
        System.out.println("欢迎使用单元测试方法【shiheng_24()_20210721174640】");
        System.out.println("此方法测试描述：【collectingAndThen的用法使用】");


        /**
         * collectingAndThen共有两个参数
         * Collector<T,A,R> downstream,Function<R,RR> finisher
         * 对Collector进行操作，操作的结果再利用Function整体Stream操作
         */
        Stream<Integer> limit = Stream.iterate(0, i -> i = i + 1).limit(100);
        Collection<List<Integer>> collect = limit.collect(Collectors.collectingAndThen(Collectors.groupingBy(Integer::intValue), a -> a.values()));
        System.out.println(JSONObject.toJSONString(collect));


        /**
         * 复杂案例示例：
         * Map<Integer, List<ShopAndPlatformShopsDTO>> tagIdAndShopsMap = selectByDimPshopIds(platformShopMap.keySet())
         *                 .stream().filter(brandTagPlatformShop -> tagMap.containsKey(brandTagPlatformShop.getTagId())).collect(
         *                         Collectors.groupingBy(BrandTagPlatformShop::getTagId,
         *                                 Collectors.collectingAndThen(Collectors.toList(),
         *                                         brandTagPlatformShops -> {
         *                                             Map<Long, List<PlatformShopDTO>> shopIdAndPlatformShopMap = brandTagPlatformShops.stream().map(BrandTagPlatformShop::getDimPshopId)
         *                                                     .distinct().filter(platformShopMap::containsKey).map(platformShopMap::get)
         *                                                     .collect(Collectors.groupingBy(PlatformShopDTO::getShopId));
         *                                             return shopIdAndPlatformShopMap.entrySet().stream().map(entry ->
         *                                                     new ShopAndPlatformShopsDTO(entry.getKey(), shopIdAndShopNameMap.get(entry.getKey()),shopIdAndShopNameMapProvince.get(entry.getKey()),labelMap.get(entry.getKey()), entry.getValue())
         *                                             ).collect(Collectors.toList());
         *                                         }
         *                                 )
         *                         ));
         */


    }


    @Test
    public void shiheng_23_20210721163756() {
        System.out.println("欢迎使用单元测试方法【shiheng_23()_20210721163756】");
        System.out.println("此方法测试描述：【MAP与FlapMap的使用理解】");


        List<Integer> collect = Stream.iterate(1, i -> i + 1).limit(1000).collect(Collectors.toList());
        List<List<Integer>> partition = Lists.partition(collect, 200);
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("普通Stream耗时");
        partition.stream().forEach(list -> {
            System.out.println(JSONObject.toJSONString(list));
        });
        stopWatch.stop();
        System.out.println("------------------------");
        stopWatch.start("parallelStream耗时");
        partition.parallelStream().forEach(list -> {
            System.out.println(JSONObject.toJSONString(list));
        });
        stopWatch.stop();

        System.out.println("--------------------");

        //partition.stream().flatMap(list)

        /**
         * 讲解：
         * flatMap接收的是Stream参数，参数示例
         * 原数据：["1-1.1","2-2.2","3-3.3"]
         * 操作：  .flatMap(v -> Arrays.stream(v.split("-")))
         * 结果集: ["1","1.1","2","2.2","3","3.3"]
         *
         * 说明：这里把多个集合["1","1.1"],["2","2.2"],["3","3.3"]合到一个集合里
         */
        Stream<SimpleClass> simpleClassStream = Stream.of(new SimpleClass("1-1.1"), new SimpleClass("2-2.2"), new SimpleClass("3-3.3"));
        Stream<String> stringStream = simpleClassStream.parallel().map(SimpleClass::getName);
        List<String> collect1 = stringStream.flatMap(v -> Arrays.stream(v.split("-"))).collect(Collectors.toList());
        System.out.println(JSONObject.toJSONString(collect1));
        System.out.println("--------------------");

        System.out.println(stopWatch.prettyPrint());


    }


    @Test
    public void shiheng_12_20210611164222() {
        System.out.println("欢迎使用单元测试方法【shiheng_12()_20210611164222】");
        System.out.println("此方法测试描述：【】");


        //1.获取stream流[实现Collection的接口接可以通过stream获取Stream流]
        new ArrayList<>().stream();
        new Vector<>().stream();
        new LinkedHashSet<>().stream();

        //MAP则可以通过
        new HashMap<>().keySet().stream();
        new HashMap<>().values().stream();
        new HashMap<>().entrySet().stream();

        //2.数组对象添加默认方法
        Stream<String> stringStream = Stream.of("1", "2", "3");

        Integer[] arr = {1, 2, 3};
        Stream<Integer> arr1 = Stream.of(arr);
        arr1.forEach(System.out::println);


        System.out.println("------------");
        //3.常用集合Stream注意事项(重要)-Stream只能操作一次-Stream方法返回的是新的流-Stream不调用终结方法，中间的操作不会执行
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
        System.out.println(Stream.of(1, 2, 3, 4, 5, 6).limit(3).count());
        Stream.of(1, 2, 3, 4, 5, 6).skip(3).forEach(System.out::println);
        Stream.of(1, 2, 3, 4, 5, 6).map(Integer::toHexString).forEach(System.out::println);
        Stream.of(1, 2, 3, 4, 5, 6).sorted((a, b) -> a * b).forEach(System.out::println);


        System.out.println("-----------");
        //注意match是一个终结方法
        //boolean anyMatch(Predicate<? super T> predicate); // 元素是否有任意一个满足条件
        //boolean allMatch(Predicate<? super T> predicate); // 元素是否都满足条件
        //boolean noneMatch(Predicate<? super T> predicate); // 元素是否都不满足条件
        System.out.println(Stream.of(1, 2, 3, 4, 5, 6).anyMatch(i -> i.equals(1)));
        System.out.println(Stream.of(1, 2, 3, 4, 5, 6).noneMatch(i -> i.equals(1)));
        System.out.println(Stream.of(1, 2, 3, 4, 5, 6).allMatch(i -> i.equals(1)));


        System.out.println("---------");
        System.out.println(Stream.of(1, 2, 3, 4, 5, 6).findFirst());
        System.out.println(Stream.of(1, 2, 3, 4, 5, 6, 1).findAny());

    }


    @Test
    public void shiheng_68_20210616171222() {
        System.out.println("欢迎使用单元测试方法【shiheng_68()_20210616171222】");
        System.out.println("此方法测试描述：【reduce的使用】");


        /**
         *示例说明：
         *  [1,2,3,4].reduce(0, (a, b),(c,d)
         *----≥ 如果是并行的(c,d)才会生效，会拿到（a,b）的计算结果进行复制给c,d计算
         *----≥ 如果是非并行的（c,d）会无效，不参与计算
         *----≥ 如果是非并行的-如果存在0，则会将数据0,1赋值给a,b，然后a,b计算的结果赋值给a，2赋值给b，重新参与计算，循环
         *----≥ 如果是并行的，则会将数据0赋值给a的arr.length次，然后将1,2,3,4赋值给b这时候四组分别参与计算，然后在得出结果在计算（分别赋值）
         */

        System.out.println(Stream.of(1, 2, 3, 4, 5, 6).min((a, b) -> a - b));
        System.out.println(Stream.of(1, 2, 3, 4, 5, 6).max((a, b) -> a - b));

        //如果Stream是非并行的，combiner不生效；
        //其计算过程与两个参数时的Reduce基本是一致的。
        //如Stream中包含了N个元素，其计算过程使用Java代码表述如
        System.out.println("-------------------1");
        Integer reduce = Stream.of(5, 6, 7, 8).parallel().reduce(0, (a, b) -> {
            System.out.println("a-->" + a);
            System.out.println("b--<" + b);
            return a - b;
        }, (c, d) -> {
            System.out.println("c-->" + c);
            System.out.println("d--<" + d);
            return c + d;
        });
        System.out.println(reduce);
        System.out.println("-------------------2");
        //测试Stream非并行的，combiner（后面一个 (c, d)）不生效；
        Integer reduce2 = Stream.of(5, 6, 7, 8).reduce(0, (a, b) -> {
            System.out.println("a-->" + a);
            System.out.println("b--<" + b);
            return a - b;
        }, (c, d) -> {
            System.out.println("c-->" + c);
            System.out.println("d--<" + d);
            return c + d;
        });
        System.out.println(reduce2);

        System.out.println("-------------------3");

        Integer reduce1 = Stream.of(5, 6, 7).reduce(0, (c, d) -> {
            System.out.println("c-->" + c);
            System.out.println("d--<" + d);
            return c + d;
        });
        System.out.println(reduce1);

        System.out.println("-------------------4");
        Integer integer = Stream.of(5, 6, 7).reduce((c, d) -> {
            System.out.println("c-->" + c);
            System.out.println("d--<" + d);
            return c + d;
        }).get();
        System.out.println(integer);
        System.out.println("-------------------5");

        Stream<Integer> integerStream = Stream.of("a", "b", "c", "d", "a", "c", "a")
                .map(ch -> "a".equals(ch) ? 1 : 0);
        Integer count = integerStream.reduce(0, Integer::sum);
        System.out.println(count);

    }


    @Test
    public void shiheng_111_20210616183103() {
        System.out.println("欢迎使用单元测试方法【shiheng_111()_20210616183103】");
        System.out.println("此方法测试描述：【】");

        Stream<String> stream1 = Stream.of("a", "b", "c");
        Stream<String> stream2 = Stream.of("x", "y", "z");
        // 通过concat方法将两个流合并为一个新的流
        Stream.concat(stream1, stream2).forEach(System.out::println);


        //concat将流合并
        Stream<String> stream3 = Stream.of("a", "b", "c");
        Stream<String> stream4 = Stream.of("x", "y", "z");

        Stream.concat(stream3, stream4).map(SimpleClass::new).forEach(System.out::println);


        //汇总
        System.out.println(Stream.of(new SimpleClass("1", 1), new SimpleClass("2", 2), new SimpleClass("3", 3)).collect(Collectors.summarizingInt(SimpleClass::getAge)));
        //最大数据
        System.out.println(Stream.of(new SimpleClass("1", 1), new SimpleClass("2", 2), new SimpleClass("3", 3)).collect(Collectors.maxBy((a, b) ->
                {
                    System.out.println("a-->" + a.getAge());
                    System.out.println("b-->" + b.getAge());
                    return a.getAge() / -b.getAge();
                }
        )));

    }


    @Test
    public void shiheng_146_20210617110651() {
        System.out.println("欢迎使用单元测试方法【shiheng_146()_20210617110651】");
        System.out.println("此方法测试描述：【】");

        //分组
        Map<String, List<SimpleClass>> collect = Stream.of(new SimpleClass("1", 1), new SimpleClass("2", 2), new SimpleClass("3", 3)).collect(Collectors.groupingBy(SimpleClass::getName));
        System.out.println(JSONObject.toJSONString(collect));

        Map<String, List<SimpleClass>> collect2 = Stream.of(new SimpleClass("1", 1), new SimpleClass("2", 2), new SimpleClass("3", 3)).collect(Collectors.groupingBy(SimpleClass::getName, Collectors.toList()));
        System.out.println(JSONObject.toJSONString(collect2));

        Map<String, Map<Integer, List<SimpleClass>>> collect3 = Stream.of(new SimpleClass("1", 1), new SimpleClass("2", 2), new SimpleClass("3", 3)).collect(Collectors.groupingBy(SimpleClass::getName, Collectors.groupingBy(SimpleClass::getAge)));
        System.out.println(JSONObject.toJSONString(collect3));

        LinkedHashMap<String, Map<Integer, List<SimpleClass>>> collect1 = Stream.of(new SimpleClass("1", 1), new SimpleClass("2", 2), new SimpleClass("3", 3)).collect(Collectors.groupingBy(SimpleClass::getName, LinkedHashMap::new, Collectors.groupingBy(SimpleClass::getAge)));
        System.out.println(JSONObject.toJSONString(collect1));


        //Collectors.partitioningBy会根据值是否为true,把集合中的数据分割为两个列表，一个true列表，一个false列表
        Map<Boolean, Set<SimpleClass>> collect4 = Stream.of(new SimpleClass("1", 1), new SimpleClass("2", 2), new SimpleClass("3", 3)).collect(Collectors.partitioningBy((p -> p.getAge() >= 2), Collectors.toSet()));
        System.out.println(JSONObject.toJSONString(collect4));


        //拼接操作
        String collect5 = Stream.of(new SimpleClass("1", 1), new SimpleClass("2", 2), new SimpleClass("3", 3)).map(SimpleClass::getName).collect(Collectors.joining("_", "pre", "suf"));
        System.out.println(collect5);


    }

    @Test
    public void shiheng_178_20210617113242() {
        System.out.println("欢迎使用单元测试方法【shiheng_178()_20210617113242】");
        System.out.println("此方法测试描述：【】");


        List<Integer> list = new ArrayList<>();
        // 通过List 接口 直接获取并行流
        Stream<Integer> integerStream = list.parallelStream();
        // 将已有的串行流转换为并行流
        Stream<Integer> parallel = Stream.of(1, 2, 3).parallel();


        Stream.iterate(1, i -> i + 1).limit(100)
                .parallel() // 将流转换为并发流，Stream处理的时候就会通过多线程处理
                .filter(s -> {
                    System.out.println(Thread.currentThread() + " s=" + s);
                    return s > 2;
                }).count();
    }


    @Data
    class SimpleClass {

        private String name;

        private Integer age;

        private List<SimpleClass> child;

        public SimpleClass() {
        }

        public SimpleClass(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public SimpleClass(String name) {
            this.name = name;
        }

        public SimpleClass(Integer age) {
            this.age = age;
        }

        public SimpleClass(String name, Integer age, List<SimpleClass> child) {
            this.name = name;
            this.age = age;
            this.child = child;
        }
    }


}
